package main

import (
	"errors"
	"fmt"
)

/**
内部实现了error接口 任何实现了 Error() string 方法的类型都可以作为错误类型。
*/

// 函数通常返回一个错误类型作为最后一个返回值：
func doSomething() error {
	// 执行操作
	if true {
		// 创建错误
		return errors.New("something went wrong")
	}
	return nil
}

// 使用 fmt.Errorf 格式化错误信息：
func doSomething2() error {
	// 执行操作
	name := "Go"
	if true {
		// 创建错误
		return fmt.Errorf("something went wrong", name)
	}
	return nil
}

// 自定义错误类型
type MyError struct {
	Code int
	Msg  string
}

// 实现 error 接口的唯一方法 Error() string，返回错误的描述信息：
// MyError 就是一个符合 error 接口的类型。
func (e *MyError) Error() string {
	return fmt.Sprintf("Code %d: %s", e.Code, e.Msg)
}

func doSomething3() error {
	// 执行操作
	if true {
		// 创建错误
		return &MyError{Code: 123, Msg: "something went wrong"}
	}
	return nil
}

/**

panic 用于触发运行时错误，类似于抛出异常。
当程序执行到 panic，当前函数会停止执行，开始逐层向上回退（unwind）调用栈，执行每层函数中的 defer，直到程序终止或被 recover 捕获。

recover 用于从 panic 中恢复，阻止程序崩溃。
只能在 defer 函数中调用有效，返回传入 panic 的值。
如果不调用 recover，程序会崩溃并打印 panic 信息。

defer 用于注册延迟调用的函数，当前函数返回前执行。
常用于资源释放、异常处理等场景。
在 panic 发生时，defer 依然会被执行。
*/

// 可能会触发 panic 的函数
func mayPanic() {
	// mayPanic() 函数中调用了 panic，触发异常。
	panic("something went wrong!")
}

// 包装函数，使用 defer + recover 捕获 panic
// safeCall() 中用 defer 注册了一个匿名函数，里面调用 recover() 捕获异常。
func safeCall() {
	// 所有注册的 defer 函数会按照后进先出（LIFO）顺序依次执行
	defer func() {
		// 如果没有 recover()，程序会打印 panic 信息并退出。
		if r := recover(); r != nil {
			fmt.Println("Recovered from panic:", r)
		}
	}()

	// 捕获后程序不会崩溃，继续执行后续代码。
	fmt.Println("Calling mayPanic()...")
	mayPanic()
	fmt.Println("This line will NOT be executed because of panic above.")
}

func main() {

	err := doSomething()
	if err != nil {
		// 处理错误
		fmt.Println("Error:", err)
	}
	// 调用doSomething3()
	err3 := doSomething3()
	if err3 != nil {
		// 处理错误
		fmt.Println("Error:", err3)
	}

	safeCall()

}
